package cn.jolyoulu.common.core.utils.other;

import cn.jolyoulu.common.core.cache.def.DefaultLocalCacheBootStrap;
import cn.jolyoulu.common.core.listeners.SpringEventListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: JolyouLu
 * @Date: 2023/12/16 17:32
 * @Description 反射工具类
 */
@Slf4j
public class ReflectUtils {

    private ReflectUtils() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * 调用类的构造方法
     * 可以获取类的构造方法，包括private、protected和默认（包访问权限）的字段，但不包括从父类继承的字段。
     *
     * @param classType      类型
     * @param parameterTypes 构造方法参数列表
     * @return
     */
    public static <T> T newInstance(Class<T> classType, Class<?>[] parameterTypes, Object[] args) {
        try {
            Constructor<T> constructor;
            if (Objects.isNull(parameterTypes) || parameterTypes.length == 0) {
                constructor = classType.getDeclaredConstructor();
                return constructor.newInstance();
            } else {
                constructor = classType.getDeclaredConstructor(parameterTypes);
                return constructor.newInstance(args);
            }
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
                 InvocationTargetException e) {
            log.error("getDeclaredFieldValue error", e);
            return null;
        }
    }

    /**
     * 获取类中的属性值
     * 可以获取类中所有声明的属性，包括private、protected和默认（包访问权限）的字段，但不包括从父类继承的字段。
     *
     * @param target    目标对象
     * @param fieldName 属性名
     * @return
     */
    public static Object getDeclaredFieldValue(Object target, String fieldName) {
        Class<?> classType = target.getClass();
        try {
            Field field = classType.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(target);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("getDeclaredFieldValue error", e);
            return null;
        }
    }

    /**
     * 修改类中的属性值
     * 可以获取类中所有声明的属性，包括private、protected和默认（包访问权限）的字段，但不包括从父类继承的字段。
     *
     * @param target    目标对象
     * @param fieldName 属性名
     * @param value     属性值
     * @return
     */
    public static void setDeclaredFieldValue(Object target, String fieldName, Object value) {
        Class<?> classType = target.getClass();
        try {
            Field field = classType.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(target, value);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("setDeclaredFieldValue error", e);
        }
    }

    /**
     * 调用类中的方法
     * 可以获取类中所有声明的方法，包括private、protected和默认（包访问权限）的字段，但不包括从父类继承的字段。
     *
     * @param target         执行该方法的目标对象
     * @param methodName     方法名称
     * @param parameterTypes 方法参数列表
     * @param args           调用该方法时的参数
     * @return 调用方法后返回值
     */
    public static Object invokeDeclaredMethod(Object target, String methodName, Class<?>[] parameterTypes, Object[] args) {
        //获取对象类型
        Class<?> classType = target.getClass();
        try {
            Method method;
            if (Objects.isNull(parameterTypes) || parameterTypes.length == 0) {
                method = classType.getDeclaredMethod(methodName);
            } else {
                method = classType.getDeclaredMethod(methodName, parameterTypes);
            }
            method.setAccessible(true);
            return method.invoke(target, args);
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            log.error("invokeDeclaredMethod error", e);
            return null;
        }
    }

    /**
     * 产生一个代理对象
     *
     * @param loader          类加载器
     * @param targetInterface 代理的目标接口
     * @param handler         目标接口方法被调用时回调该方法，记得最后：return proxy
     * @param <T>             接口类型
     * @return
     */
    public static <T> T newProxyInstance(ClassLoader loader,
                                         Class<T> targetInterface,
                                         InvocationHandler handler) {
        @SuppressWarnings("unchecked")
        T res = (T) Proxy.newProxyInstance(
                loader,
                new Class[]{targetInterface},
                handler
        );
        return res;
    }

    /**
     * 获取类继承的父类泛型参数列表
     *
     * @param classType 类型
     * @return
     */
    public static List<Class<?>> getSuperclassGenerics(Class<?> classType) {
        Type type = classType.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] argType = ((ParameterizedType) type).getActualTypeArguments();
            return Stream.of(argType).map(m -> (Class<?>) m).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    /**
     * 获取类实现的接口泛型参数列表
     *
     * @param classType 类型
     * @return
     */
    public static List<Class<?>> getInterfacesGenerics(Class<?> classType) {
        List<Class<?>> res = new ArrayList<>();
        Type[] types = classType.getGenericInterfaces();
        for (Type type : types) {
            if (type instanceof ParameterizedType) {
                Type[] argType = ((ParameterizedType) type).getActualTypeArguments();
                res.addAll(Stream.of(argType).map(m -> (Class<?>) m).collect(Collectors.toList()));
            }
        }
        return res;
    }

    /**
     * 获取类实现的接口泛型参数列表
     *
     * @param classType 类型
     * @param interfaceType 要查找的接口类型
     * @return
     */
    public static List<Class<?>> getInterfacesGenerics(Class<?> classType,Class<?> interfaceType) {
        Type[] types = classType.getGenericInterfaces();
        for (Type type : types) {
            if (type instanceof ParameterizedType) {
                if (((ParameterizedType) type).getRawType().equals(interfaceType)) {
                    Type[] argType = ((ParameterizedType) type).getActualTypeArguments();
                    return Stream.of(argType).map(m -> (Class<?>) m).collect(Collectors.toList());
                }
            }
        }
        return Collections.emptyList();
    }


    public static void main(String[] args) {
        List<Class<?>> generics = ReflectUtils.getInterfacesGenerics(SpringEventListener.class, ApplicationListener.class);
        System.out.println(generics);
    }
}
